﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Space_Cleaner.Utils;

namespace Space_Cleaner.SpaceCleaner
{
    class SC_SpaceObject
    {
        private const float G = 1.0f;

        protected Texture2D texture;
        protected Vector2 textureCenter;
        
        protected Vector2 position;
        protected Vector2 velocity;
        protected Vector2 acceleration;
        private float mass;
        
        protected Vector2 force;

        protected float rotation;
        protected float rotationVel = 0.0f;
        protected float rotationAbsorption = 0.0f;
        protected Boolean physics;

        protected float size = 1.0f;

        protected float collisionRadius = 0.0f;

        protected Boolean activated = true;

        public SC_SpaceObject(Vector2 _position, Texture2D _texture)
            : this(_position, 0, 0, _texture)
        {
        }

        public SC_SpaceObject(Vector2 _position, float _mass, float _collisionRadius, Texture2D _texture)
        {
            this.position = _position;
            this.acceleration = Vector2.Zero;
            this.mass = _mass;
            if (mass <= 0)
                this.physics = false;
            else
                this.physics = true;
            this.collisionRadius = _collisionRadius;
            this.force = Vector2.Zero;
            this.texture = _texture;
            this.textureCenter = new Vector2(texture.Width / 2.0f, texture.Height / 2.0f) * size;
        }

        //SimpleConstructor
        public SC_SpaceObject()
        {
            texture = null;
            textureCenter = Vector2.Zero;

            position = Vector2.Zero;
            acceleration = Vector2.Zero;
            velocity = Vector2.Zero;
            mass = 1;
            
            force = Vector2.Zero;
            
            rotation = 0;
            physics = true;
        }

        //copy function
        public virtual void CopyValues(SC_SpaceObject _SpaceObject, float _Scale)
        {
            //scaleable values
            size = _SpaceObject.Size * _Scale;
            mass = _SpaceObject.Mass * _Scale;
            collisionRadius = _SpaceObject.collisionRadius;//collisionsradius isnt scaled

            //texture = _SpaceObject.Texture;
            //textureCenter = new Vector2(texture.Width / 2.0f, texture.Height / 2.0f) * size;
            position = _SpaceObject.Position;
            velocity = _SpaceObject.Velocity;
            force = _SpaceObject.Force;
            physics = _SpaceObject.hasPhyiscs;

            rotation = _SpaceObject.rotation;// 0.0f;
            rotationVel = _SpaceObject.rotationVel;// 0.0f;
            acceleration = Vector2.Zero;
            
        }

        public Texture2D Texture
        {
            get { return this.texture; }
            set
            {
                texture = value;
                textureCenter = new Vector2(texture.Width / 2.0f, texture.Height / 2.0f) * size;
            }
        }

        public float CollisionRadius
        {
            get { return this.collisionRadius * this.size; }
        }

        public float Mass
        {
            get { return this.mass; }
        }

        public float Size
        {
            get { return size; }
            set { size = value; }
        }

        public float Rotation
        {
            get { return rotation; }
            set { rotation = value; }
        }

        public Boolean hasPhyiscs
        {
            get { return this.physics; }
        }

        public Vector2 Position
        {
            get { return this.position; }
            set { position = value; }
        }

        public Vector2 Velocity
        {
            get { return this.velocity; }
            set { velocity = value; }
        }

        public Boolean Activated
        {
            get { return this.activated; }
            set { activated = value; }
        }

        public Vector2 Force
        {
            get { return this.force; }
        }

        public void resetForce()
        {
            this.force = Vector2.Zero;
        }

        public virtual void draw(SpriteBatch _spriteBatch, SC_Display _display)
        {
            if (Activated)
            {
                Vector2 relativePosition = _display.getRelativePosition(position);
                _spriteBatch.Draw(texture, relativePosition, null, Color.White, rotation, textureCenter, _display.Scale * this.size, SpriteEffects.None, 0f);
            }
        }

        public virtual void update(TimeSpan elapsedTime)
        {
            if (Activated)
            {
                rotationVel /= 1.0f + this.rotationAbsorption;
                rotation += rotationVel * elapsedTime.Milliseconds;
                if (physics)
                {
                    acceleration = this.force / this.mass;
                    velocity += acceleration * (elapsedTime.Milliseconds == 0 ? 1 : elapsedTime.Milliseconds);
                    position += velocity * elapsedTime.Milliseconds;
                }
            }
        }

        public void addForce(Vector2 _force)
        {
            this.force += _force;
        }

        public void addGravityForceOf(SC_SpaceObject _object)
        {
            addGravityForceOf(_object, 1.0f);
        }

        public void addGravityForceOf(SC_SpaceObject _object,float _ratio)
        {
            if (_object != null)
            {
                Vector2 distV = this.Position - _object.Position;
                float dist = distV.Length();

                float F = G * this.Mass * _object.Mass / (float)Math.Pow(dist, 2);

                distV.Normalize();
                this.addForce(distV * -F * _ratio);
            }
        }

        protected void drawOrbit(SC_SpaceObject obj, SpriteBatch _spriteBatch, SC_Display _display)
        {
            if (obj == null || obj.Activated == false) return;
            SC_SpaceObject Temp;
            PrimitiveLine Line = new PrimitiveLine(_spriteBatch.GraphicsDevice);
            TimeSpan Time = TimeSpan.FromMilliseconds(100.0);
            SC_Earth earth = SC_World.getInstance().getEarth();


            if (obj is SC_Satellite)
            {
                Line.Colour = Color.YellowGreen;
            }

            if (obj is SC_Rocket)
            {
                Line.Colour = Color.YellowGreen;
                Time = TimeSpan.FromMilliseconds(16.0); //Unangenehmerwiese hangt die Flugbahn der Rackete extrem von dem Zeitintervall ab, 16 entspricht ungefaer dem normalen zeitintervall 
                Temp = new SC_Rocket();
                Temp.CopyValues(obj, 1);
                ((SC_Rocket)Temp).start();

                while (true)
                {
                    Temp.update(Time);
                    if (Temp.Activated == false) break;
                    Line.AddVector(_display.getRelativePosition(Temp.Position));
                }

                drawOrbit(((SC_Rocket)Temp).MySatelite, _spriteBatch, _display);
            }
            else
            {
                Temp = new SC_SpaceObject();
                Temp.CopyValues(obj, 1);
                Temp.Activated = true;

                for (int i = 0; i <= 2000; i++)
                {
                    if (obj is SC_SpaceCraft)
                        Temp.addGravityForceOf(earth, 0.01f);
                    else
                        Temp.addGravityForceOf(earth);

                    Temp.update(Time);
                    Temp.resetForce();
                    if (obj is SC_Satellite && Collision.doSimpleCollisionDetection(Temp))
                    {
                        Line.Colour = Color.Red;
                        Temp.drawCollisionRadius(_spriteBatch, _display);
                        break;
                    }
                    if (Collision.intersect(earth, Temp))
                        break;
                    Line.AddVector(_display.getRelativePosition(Temp.Position));
                }
            }
            Line.Render(_spriteBatch);
        }

        public void drawCollisionRadius(SpriteBatch _spriteBatch, SC_Display _display)
        {
            PrimitiveLine Line = new PrimitiveLine(_spriteBatch.GraphicsDevice);
            Line.Colour = Color.Red;
            Line.CreateCircle(_display.Scale * CollisionRadius, 16, _display.getRelativePosition(position));
            Line.Render(_spriteBatch);
        }
    }
}
